package com.shanzmoo.db.sys.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shanzmoo.base.constant.Constant;
import com.shanzmoo.base.bean.SResponse;
import com.shanzmoo.db.sys.entity.MenuEntity;
import com.shanzmoo.db.sys.entity.dto.MenuSaveDto;
import com.shanzmoo.db.sys.entity.dto.MenuUpdateDto;
import com.shanzmoo.db.sys.entity.vo.MenuAuthVo;
import com.shanzmoo.db.sys.entity.vo.MenuTreeVo;
import com.shanzmoo.db.sys.entity.vo.MenuVo;
import com.shanzmoo.db.sys.mapper.MenuMapper;
import com.shanzmoo.db.sys.service.IMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单表 服务实现类
 * </p>
 *
 * @author Gzhao
 * @since 2020-11-10
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements IMenuService {

    @Override
    public SResponse<Boolean> add(MenuSaveDto saveDto, Integer currentUserId) {
        MenuEntity menuEntity = MenuSaveDto.converted(saveDto);
        if (StrUtil.isBlank(saveDto.getComponentPath())) {
            saveDto.setComponentPath(null);
        }
        menuEntity.setCreateUser(currentUserId);
        baseMapper.insert(menuEntity);
        return SResponse.ok();
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public SResponse<Boolean> deleteById(Integer menuId, Integer currentUserId) {
        MenuEntity menuEntity = new MenuEntity();
        menuEntity.setMenuId(menuId);
        menuEntity.setDeleted(true);
        menuEntity.setUpdateUser(currentUserId);

        List<MenuEntity> children = baseMapper.selectList(
                new QueryWrapper<MenuEntity>()
                        .eq("deleted", false)
                        .eq("parent_id", menuId)
        );
        if (CollectionUtil.isNotEmpty(children)) {
            return SResponse.fail(Constant.ERRCODE_LOGIC, "请确认当前菜单没有子菜单后再删除！");
        }

        int re = baseMapper.updateById(menuEntity);
        if (re > 0) {
            return SResponse.ok();
        }

        return SResponse.fail(Constant.ERRCODE_DATABASE_OPERATION, "菜单不存在，删除失败");
    }

    @Override
    public SResponse<Boolean> editMenu(MenuUpdateDto updateDto, Integer currentUserId) {
        MenuEntity menuEntity = MenuUpdateDto.converted(updateDto);
        menuEntity.setUpdateUser(currentUserId);

        int re = baseMapper.updateById(menuEntity);
        if (re > 0) {
            return SResponse.ok();
        }

        return SResponse.fail(Constant.ERRCODE_DATABASE_OPERATION, "菜单不存在，删除失败");
    }

    @Override
    public SResponse<List<MenuAuthVo>> getAuthTree(Integer currentUserId) {
        List<MenuEntity> allList = getListByUserId(currentUserId);

        if (CollectionUtil.isEmpty(allList)) {
            return SResponse.ok(Collections.EMPTY_LIST);
        }

        // 一级目录
        List<MenuAuthVo> fristLevelMenu = allList.stream()
                .filter(e -> e.getParentId() == 0)
                .map(e -> {
                    return MenuAuthVo.create(e);
                })
                .sorted(Comparator.comparingInt(MenuAuthVo::getMenuIndex))
                .collect(Collectors.toList());

        fristLevelMenu.forEach(root -> {
            findChildren(root, allList);
        });

        return SResponse.ok(fristLevelMenu);
    }

    @Override
    public SResponse<List<MenuTreeVo>> getBriefTree() {
        List<MenuEntity> allList = baseMapper.selectList(new QueryWrapper<MenuEntity>().eq("deleted", false));

        // 菜单只到二级
        if (CollectionUtil.isEmpty(allList)) {
            return SResponse.ok(Collections.EMPTY_LIST);
        }
        // 目录
        List<MenuTreeVo> fristLevelMenu = allList.stream()
                .filter(e -> e.getMenuType() == 0)
                .map(e -> {
                    return MenuTreeVo.create(e);
                }).collect(Collectors.toList());

        fristLevelMenu.forEach(e -> {
            // 菜单
            List<MenuTreeVo> secondLevelMenuList = allList.stream()
                    .filter(child -> Objects.equals(child.getParentId(), e.getMenuId())
                            && child.getMenuType() == 1)
                    .map(MenuTreeVo::create)
                    .collect(Collectors.toList());

            if (CollectionUtil.isEmpty(secondLevelMenuList)) {
                return;
            }

            e.setChildren(secondLevelMenuList);
            secondLevelMenuList.forEach(secondMenu -> {
                // 按钮
                List<MenuTreeVo> thridLevelMenuList = allList.stream()
                        .filter(child -> Objects.equals(child.getParentId(), secondMenu.getMenuId())
                                && child.getMenuType() == 1)
                        .map(obj -> {
                            return MenuTreeVo.create(obj);
                        }).collect(Collectors.toList());
                secondMenu.setChildren(CollectionUtil.isNotEmpty(thridLevelMenuList) ? thridLevelMenuList : null);
                thridLevelMenuList.forEach(thridMenu -> {
                    // 按钮
                    List<MenuTreeVo> buttonList = allList.stream()
                            .filter(child -> Objects.equals(child.getParentId(), thridMenu.getMenuId())
                                    && child.getMenuType() == 2)
                            .map(MenuTreeVo::create)
                            .collect(Collectors.toList());
                    thridMenu.setChildren(CollectionUtil.isNotEmpty(buttonList) ? buttonList : null);
                });
            });
        });
        return SResponse.ok(fristLevelMenu);
    }

    @Override
    public SResponse<List<MenuVo>> getAllTree() {
        List<MenuEntity> allList = baseMapper.selectList(new QueryWrapper<MenuEntity>().eq("deleted", false));
        if (CollectionUtil.isEmpty(allList)) {
            return SResponse.ok(Collections.emptyList());
        }

        // 一级目录
        List<MenuVo> fristLevelMenu = allList.stream()
                .filter(e -> e.getParentId() == 0)
                .map(e -> {
                    return MenuVo.create(e);
                })
                .sorted(Comparator.comparingInt(MenuVo::getMenuIndex))
                .collect(Collectors.toList());

        fristLevelMenu.forEach(root -> {
            findChildren2(root, allList);
        });

        return SResponse.ok(fristLevelMenu);
    }

    @Override
    public List<MenuEntity> getListByUserId(Integer userId) {
        return baseMapper.getListByUserId(userId);
    }


    private void findChildren(MenuAuthVo root, List<MenuEntity> allList) {
        List<MenuAuthVo> children = allList.stream()
                .filter(child -> Objects.equals(child.getParentId(), root.getMenuId()))
//                .filter(child -> Objects.equals(child.getParentId(), root.getMenuId()) && child.getMenuType() != 2)
                .map(MenuAuthVo::create)
                .sorted(Comparator.comparingInt(MenuAuthVo::getMenuIndex))
                .collect(Collectors.toList());
        // 没有子菜单，跳出循环
        if (CollectionUtil.isEmpty(children)) {
            return;
        }

        children.forEach(child -> {
            findChildren(child, allList);
        });

        root.setChildren(children);
    }

    private void findChildren2(MenuVo root, List<MenuEntity> allList) {
        List<MenuVo> children = allList.stream()
                .filter(child -> Objects.equals(child.getParentId(), root.getMenuId()))
                .map(MenuVo::create)
                .sorted(Comparator.comparingInt(MenuVo::getMenuIndex))
                .collect(Collectors.toList());
        // 没有子菜单，跳出循环
        if (CollectionUtil.isEmpty(children)) {
            return;
        }

        children.forEach(child -> {
            findChildren2(child, allList);
        });

        root.setChildren(children);
    }

}
